package com.java.star.mall.front.service.impl;

import com.alibaba.fastjson2.JSONObject;
import com.java.star.mall.common.constant.data.ImageConstant;
import com.java.star.mall.common.constant.data.ShowStatusConstant;
import com.java.star.mall.common.constant.web.JwtConstant;
import com.java.star.mall.common.exception.BusinessException;
import com.java.star.mall.common.response.StatusCode;
import com.java.star.mall.common.utils.Asserts;
import com.java.star.mall.front.pojo.authentication.CurrentPrincipal;
import com.java.star.mall.front.pojo.param.UserUpdateParam;
import com.java.star.mall.front.properties.ImageProperties;
import com.java.star.mall.front.properties.JwtProperties;
import com.java.star.mall.front.properties.WxProperties;
import com.java.star.mall.front.dao.mapper.WxUserMapper;
import com.java.star.mall.front.pojo.dto.OpenIdRequestDTO;
import com.java.star.mall.front.pojo.param.OpenIdRequestParam;
import com.java.star.mall.front.pojo.param.WxLoginParam;
import com.java.star.mall.front.pojo.entity.WxUser;
import com.java.star.mall.front.pojo.vo.WxLoginVO;
import com.java.star.mall.front.service.WxUserService;
import com.java.star.mall.front.util.CurrentPrincipalUtils;
import com.java.star.mall.front.util.JwtUtils;
import com.java.star.mall.front.util.RestTemplateUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.MimeTypeUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * 微信用户Service实现类
 */
@Service
public class WxUserServiceImpl implements WxUserService {

    @Autowired
    private WxProperties wxProperties;

    @Autowired
    private JwtProperties jwtProperties;

    @Autowired
    private WxUserMapper wxUserMapper;

    @Autowired
    private ImageProperties imageProperties;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public WxLoginVO login(WxLoginParam wxLoginParam) {
        //1.获取用户的openId
        String openId = getWxUserOpenId(wxLoginParam.getCode());

        //2.刷新用户数据到数据库
        WxUser wxUser = refreshWxUserInfo(wxLoginParam, openId);

        //3.装填JWT信息
        String jwt = loadingJwt(wxUser, openId);

        //4.装填响应对象
        WxLoginVO wxLoginVO = new WxLoginVO();
        BeanUtils.copyProperties(wxUser, wxLoginVO);
        wxLoginVO.setToken(jwt);

        return wxLoginVO;
    }

    /**
     * 获取微信用户的openId
     *
     * @param code 登录时获取的 code
     * @return openId 微信用户的唯一ID
     */
    private String getWxUserOpenId(String code) {
        //进行请求参数装填
        OpenIdRequestParam openIdRequestParam = new OpenIdRequestParam();
        BeanUtils.copyProperties(wxProperties, openIdRequestParam);
        openIdRequestParam.setJsCode(code);

        //远程调用微信code2Session接口获取用户openId
        String result = RestTemplateUtils.get(wxProperties.getLogin().getUrl(), openIdRequestParam);
        OpenIdRequestDTO openIdRequestDTO = JSONObject.parseObject(result, OpenIdRequestDTO.class);
        String openId = openIdRequestDTO.getOpenId();

        //效验调用结果
        Asserts.isTrue(openId == null, StatusCode.APP_ERROR, "登录授权失败");

        //返回用户openId
        return openId;
    }


    /**
     * 刷新用户信息
     *
     * @param wxLoginParam 微信登录参数
     * @param openId       微信用户openId
     * @return 数据库中的用户信息
     */
    private WxUser refreshWxUserInfo(WxLoginParam wxLoginParam, String openId) {
        //根据用户openId查询用户是否存在，不存在做默认注册操作，存在做更新操作
        WxUser wxUser = wxUserMapper.getWxUserByOpenId(openId);
        if (wxUser == null) {
            wxUser = new WxUser();
            wxUser.setNickName(wxLoginParam.getNickName());
            wxUser.setAvatarUrl(wxLoginParam.getAvatarUrl());
            wxUser.setOpenId(openId);
            wxUser.setShowStatus(ShowStatusConstant.SHOW);
            wxUserMapper.insert(wxUser);
        } else {
            wxUser.setLastLogin(new Date());
            wxUserMapper.update(wxUser);
        }
        return wxUser;
    }

    /**
     * 装填JWT
     *
     * @param wxUser 微信用户实体
     * @param openId 微信用户openId
     * @return jwt字符串
     */
    private String loadingJwt(WxUser wxUser, String openId) {
        Map<String, Object> claims = new HashMap<>();
        claims.put(JwtConstant.CLAIM_USER_ID, wxUser.getId());
        claims.put(JwtConstant.CLAIM_OPEN_ID, openId);
        Date expiration = new Date(System.currentTimeMillis() + 60 * 1000 * jwtProperties.getDurationInMinute());
        return JwtUtils.generate(claims, expiration, jwtProperties.getSecretKey());
    }

    @Override
    public String upload(MultipartFile picFile) {
        //效验图片文件
        Asserts.isTrue(picFile == null || picFile.isEmpty(),
                StatusCode.APP_ERROR, "上传图片失败，请选择您要上传的文件");

        //效验图片类型
        String contentType = picFile.getContentType();
        Asserts.isTrue(!MimeTypeUtils.IMAGE_JPEG_VALUE.equals(contentType)
                        && !MimeTypeUtils.IMAGE_PNG_VALUE.equals(contentType)
                        && !MimeTypeUtils.IMAGE_GIF_VALUE.equals(contentType),
                StatusCode.APP_ERROR, "上传图片失败，图片类型不正确");

        //获取图片存储路径
        String filePath = imageProperties.getStoragePath() + "/" + ImageConstant.AVATAR_PATH;

        //判断文件路径是否存在，不存在则创建
        File file = new File(filePath);
        if (!file.exists()) {
            Asserts.isTrue(!file.mkdir(), StatusCode.APP_ERROR, "上传图片失败，文件路径错误");
        }

        //处理新的图片名称
        String fileName = picFile.getOriginalFilename();
        String suffix = fileName.substring(fileName.lastIndexOf("."));
        fileName = UUID.randomUUID().toString().replace("-", "") + suffix;
        String storeUrlPath = filePath + "/" + fileName;
        //保存图片
        try {
            picFile.transferTo(new File(storeUrlPath));
        } catch (IOException e) {
            throw new BusinessException(StatusCode.APP_ERROR, "上传图片失败");
        }

        //返回图片访问地址
        return imageProperties.getUrl() + ImageConstant.AVATAR_PATH +  "/" + fileName;
    }

    @Override
    public void update(UserUpdateParam userUpdateParam) {
        CurrentPrincipal currentPrincipal = CurrentPrincipalUtils.getCurrentPrincipal();
        WxUser wxUser = new WxUser();
        wxUser.setId(currentPrincipal.getId());
        wxUser.setNickName(userUpdateParam.getNickName());
        wxUser.setAvatarUrl(userUpdateParam.getAvatarUrl());
        wxUserMapper.update(wxUser);
    }

}
